<script setup lang="ts">
import { ref, reactive, onMounted, computed } from "vue";
import { onBeforeRouteLeave } from "vue-router";
import {
  getProjectList,
  runProject,
  checkRun,
  stopProject,
  getYamlConfig,
  getYamlRuntime,
  getYamlExecution,
  isOpenMonitor,
  getMonitorStatus,
  getActiveMachines,
  updateDistributedValue,
  deleteScenario,
  addScenario,
  updateScenario,
  updateTime,
  getCreater,
  generateNewYaml,
  getUserIP,
  getExecutor,
  bindSlaveIP,
  getUseableSlaveIp,
  getJmeterLog,
  getTaurusLog,
  downloadJmeterLog,
  downloadTaurusLog,
  createTask,
  generateBuildYaml
} from "@/api/file";
import { downloadFileWithBuffer } from "@/utils/download";
import AddDialog from "./addDialog.vue";
import { ElMessage } from "element-plus";
import type { FormInstance, FormRules, CheckboxValueType } from "element-plus";
import Delete from "@iconify-icons/ep/delete";
import Edit from "@iconify-icons/ep/edit";
import Plus from "@iconify-icons/ep/plus";
import { dayjs } from "element-plus";
import duration from "dayjs/plugin/duration";
import relativeTime from "dayjs/plugin/relativeTime";
import "dayjs/locale/zh-cn";
import axios from "axios";
import yamlLabel from "../project/yamlLabel.json";
import YamlTable from "../project/yamlConfig.vue";
import Download from "@iconify-icons/ep/download";
// import { io } from "socket.io-client";
dayjs.extend(duration);
dayjs.extend(relativeTime);
dayjs.locale("zh-cn");

defineOptions({
  name: "Run"
});


type selection = {
  scenario?: string;
  concurrency?: string;
  targettime?: string;
};
const pagination = ref({
  total: 0,
  pageNum: 1,
  pageSize: 10,
})
const windowHeight = ref(window.innerHeight);
const activeName = ref("first");
const searchScenario = ref("");
const createrName = ref("");
const projectList = ref([]);
const jmeterLogContent = ref("");
const TaurusLogContent = ref("");
const form = ref({
  projectName: "",
  isMonitor: false,
  distributedValue: [],
  scenarioNames: [],
  bindSlaverIp: []
});
const dialogForm = ref({
  distributedValue: []
});
const dialogBindForm = ref({
  bindSlaverIp: []
});
//选择每周星期几
const checkAll = ref(false)
const isIndeterminate = ref(true)
const checkedWeek = ref([])
const weeks = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']

const handleCheckAllChange = (val: CheckboxValueType) => {
  checkedWeek.value = val ? weeks : []
  isIndeterminate.value = false
}
const handleCheckedWeekChange = (value: CheckboxValueType[]) => {
  const checkedCount = value.length
  checkAll.value = checkedCount === weeks.length
  isIndeterminate.value = checkedCount > 0 && checkedCount < weeks.length
}

const dialogTaskFormVisible = ref(false);
const showTaskDialog = async () => {
  if (!ruleFormRef.value) return;
  await ruleFormRef.value.validate();
  dialogTaskFormVisible.value = true;
  // dialogIsDisabled.value = false;

}
const TaskForm = reactive({
  taskName: '',
  distributedValue: [],
  scenarioNames: '',
  taskTime: new Date
});
const editForm = reactive({
  "scenario": "",
  "concurrency": 1,
  "targettime": 1,
  "ramp-up": 1
});

const edittimeForm = reactive({
  "Runtime": 1,
});
const distributedString = computed(() => {
  return form.value.distributedValue.join(",");
});
const multipleSelection = ref<selection[]>([]);
const dialogVisible = ref(false);
const dialogEdit = ref(false);
const dialogEdittime = ref(false);
const loading = ref(false);
const tableLoading = ref(false);
const dialogLoading = ref(false);
const dialogBindLoading = ref(false);
const output = ref("");
const currentIp = ref("");
const yamlConfig = ref({
  runtime: 0,
  execution: [],
});
const activeNames = ref([]);
const distributedOptions = ref([]);
// const count = ref(0);
const ruleFormRef = ref<FormInstance>();
const rules = reactive<FormRules>({
  projectName: [{ required: true, message: "请选择项目", trigger: "blur" }],
  distributedValue: [{ required: true, message: "选择测试机", trigger: "blur" }]

});
const dialogFormVisible = ref(false);
const dialogBindVisible = ref(false);
const source = axios.CancelToken.source();

// 更新窗口高度的函数
const updateWindowHeight = () => {
  windowHeight.value = window.innerHeight;
};
// let timer;

// 在页面离开前触发
onBeforeRouteLeave((to, from, next) => {
  source.cancel("请求被取消");
  next();
});


// 页面渲染完毕时执行
onMounted(async () => {
  await getList();
  getYaml();
  check();

});

// 获取项目列表
const getList = async () => {
  try {
    const res = await getProjectList();
    if (res.success) {
      projectList.value = res.data;
    } else {
      ElMessage.error(res.msg);
    }
  } catch (error) {
    ElMessage.error(error);
  }
};
const getCreaterInfo = async () => {
  try {
    const res = await getCreater({ projectName: form.value.projectName });
    if (res.success) {
      createrName.value = res.data;
    } else {
      ElMessage.error(res.msg);
    }
  } catch (error) {
    ElMessage.error(error);
  }
};
// 获取yaml配置
const getYaml = async () => {
  if (!form.value.projectName) {
    yamlConfig.value = {
      runtime: 0,
      execution: [],
    };
    return;
  }
  form.value.distributedValue = [];
  try {
    tableLoading.value = true;
    const res = await Promise.all([getYamlRuntime({ projectName: form.value.projectName }), getYamlExecution({ projectName: form.value.projectName, sencrioName: searchScenario.value, pageNum: pagination.value.pageNum, pageSize: pagination.value.pageSize })]);
    tableLoading.value = false;
    if (res[0].success) {
      yamlConfig.value.runtime = res[0].data.runtime;
      getMonitorStatus({ projectName: form.value.projectName }).then(res => {
        if (res.success) {
          // ElMessage.success("读取成功");
          form.value.isMonitor = res.data.status;
        } else {
          ElMessage.error(res.msg);
        }
      });
    } else {
      ElMessage.error(res[0].msg);
      yamlConfig.value.runtime = null;
    }
    if (res[1].success) {
      yamlConfig.value.execution = res[1].data.list
      pagination.value.total = res[1].data.total
    } else {
      ElMessage.error(res[1].msg);
      yamlConfig.value.execution = [];
      pagination.value.total = 0
    }

  } catch (err) {
    tableLoading.value = false;
    ElMessage.error(err);
  }
};

const handleSelectionChange = (val: selection[]) => {
  multipleSelection.value = val;
  TaskForm.scenarioNames = val.map(row => row.scenario).join(', ');
};

// 执行测试
const run = async () => {
  if (!ruleFormRef.value) return;
  await ruleFormRef.value.validate();
  try {
    const userIp = await getUserIP({ projectName: form.value.projectName });
    currentIp.value = userIp.data;
    form.value.scenarioNames = multipleSelection.value.map(item => item.scenario);
    const NewYamlRes = await generateNewYaml(form.value);
    if (NewYamlRes.success) {
      const res = await runProject(form.value);
      if (res.success) {
        console.log(res.data);
        ElMessage.success("执行成功");
        check();
      } else {
        ElMessage.error(res.msg);
      }
    } else {
      ElMessage.error(NewYamlRes.msg);
    }
  } catch (error) {
    ElMessage.error(error);
  }
};

// 执行测试
const check = async () => {
  console.log("check");
  if (!form.value.projectName) return;
  const userIp = await getExecutor({ projectName: form.value.projectName });
  currentIp.value = userIp.data;
  checkRun(form.value, { cancelToken: source.token })
    .then(res => {
      if (res.success) {
        loading.value = res.data.isRunning;
        output.value = res.data.content;
        if (res.data.isRunning) {
          setTimeout(() => {
            check();
          }, 120000);
          // check();
        }
      } else {
        ElMessage.error(res.msg);
      }
    })
    .catch(error => {
      if (axios.isCancel(error)) {
        console.log("请求已被取消", error.message);
      } else {
        ElMessage.error(error);
      }
    });
};

//构建测试任务
const submitTaskForm = async () => {
  const timestamp = new Date().getTime();
  TaskForm.taskName = `${form.value.projectName}${timestamp}`;
  console.log("任务名:", TaskForm.taskName);
  try {
    // const userIp = await getUserIP({ projectName: form.value.projectName });
    // currentIp.value = userIp.data;
    form.value.scenarioNames = multipleSelection.value.map(item => item.scenario);
    const utcDate = TaskForm.taskTime;
    const localDate = new Date(utcDate.getTime() - utcDate.getTimezoneOffset() * 60000);
    const taskData = {
      projectName: form.value.projectName,
      distributedValue: form.value.distributedValue,
      scenarioNames: form.value.scenarioNames,
      runtime: localDate,
      selectedDays: checkedWeek.value
    };
    form.value.scenarioNames = multipleSelection.value.map(item => item.scenario);
    const BuildYamlRes = await generateBuildYaml(taskData);
    if (BuildYamlRes.success) {
      const res = await createTask(taskData);
      if (res.success) {
        console.log(res.data);
        ElMessage.success("执行成功");
        check();
      } else {
        ElMessage.error(res.msg);
      }
    } else {
      ElMessage.error(BuildYamlRes.msg);
    }
  } catch (error) {
    ElMessage.error(error);
  }

  dialogTaskFormVisible.value = false;
};

const handleChange = (value: string) => {
  //sessionStorage.setItem("runProjectName", value);
  getYaml();
  check();
  getCreaterInfo();
  handleTabChange('third');
  handleTabChange('fourth');
};

const handleIsMonitor = async (value: boolean) => {
  try {
    const res = await isOpenMonitor({
      isMonitor: value,
      projectName: form.value.projectName
    });
    if (res.success) {
      // ElMessage.success(`已${value ? '开启' : '关闭'}`);
      ElMessage.success("操作成功");
      getYaml();
      check();
    } else {
      ElMessage.error(res.msg);
    }
  } catch (error) {
    ElMessage.error(error);
  }
};

const stop = async () => {
  //   source.cancel("请求被取消");
  //   source = axios.CancelToken.source();
  // try {
  const res = await stopProject({ projectName: form.value.projectName, distributedValue: form.value.distributedValue });
  if (res.success) {
    ElMessage.success("进程已清除");
    if (!form.value.projectName) return;
    const userIp = await getExecutor({ projectName: form.value.projectName });
    currentIp.value = userIp.data;
    checkRun(form.value, { cancelToken: source.token })
      .then(res => {
        if (res.success) {
          loading.value = res.data.isRunning;
          output.value = res.data.content;
          if (res.data.isRunning) {
            setTimeout(() => {
              check();
            });
            // check();
          }
        } else {
          ElMessage.error(res.msg);
        }
      })
      .catch(error => {
        if (axios.isCancel(error)) {
          console.log("请求已被取消", error.message);
        } else {
          ElMessage.error(error);
        }
      });
  }
};

const handleVisibleChange = async () => {
  try {
    dialogForm.value.distributedValue = [];
    const res = await getUseableSlaveIp({ projectName: form.value.projectName });
    if (res.success) {
      if (res.data) {
        distributedOptions.value = res.data.split(',');
      } else {
        ElMessage.warning("该项目未查到可用测试机");
        distributedOptions.value = [];
      }
      dialogFormVisible.value = true
    } else {
      ElMessage.error(res.msg);

    }
  } catch (error) {
    ElMessage.error(error);
  }
};

const handleUpdateDistributedValue = async () => {
  try {
    dialogLoading.value = true;
    const res = await updateDistributedValue({
      projectName: form.value.projectName,
      distributedValue: dialogForm.value.distributedValue
    });
    dialogLoading.value = false;
    if (res.success) {
      form.value.distributedValue = res.data;
      ElMessage.success(res.msg);
      dialogFormVisible.value = false;
    } else {
      ElMessage.error(res.msg);
    }
  } catch (error) {
    dialogLoading.value = false;
    ElMessage.error(error);
  }
};

const handleUpdateBindValue = async () => {
  try {
    dialogBindLoading.value = true;
    const res = await bindSlaveIP({
      projectName: form.value.projectName,
      slaverIp: dialogBindForm.value.bindSlaverIp
    });
    // ElMessage.success(JSON.stringify(dialogBindForm.value))
    dialogBindLoading.value = false;
    if (res.success) {
      form.value.bindSlaverIp = res.data;
      ElMessage.success(res.msg);
      dialogBindVisible.value = false;
    } else {
      ElMessage.error(res.msg);
    }
  } catch (error) {
    dialogBindLoading.value = false;
    ElMessage.error(error);
  }
};

const handleDel = async (row: { scenario: string }) => {
  try {
    loading.value = true;
    const res = await deleteScenario({
      projectName: form.value.projectName,
      scenarioName: [row.scenario]
    });
    loading.value = false;
    if (res.success) {
      getYaml();
      check();
      ElMessage.success(res.msg);
    } else {
      ElMessage.error(res.msg);
    }
  } catch (error) {
    loading.value = false;
    ElMessage.error(error);
  }
};

const handleAdd = async (scenarioName: string[]) => {
  try {
    loading.value = true;
    const res = await addScenario({
      projectName: form.value.projectName,
      scenarioName: scenarioName
    });
    loading.value = false;
    if (res.success) {
      getYaml();
      check();
      ElMessage.success(res.msg);
    } else {
      ElMessage.error(res.msg);
    }
  } catch (error) {
    loading.value = false;
    ElMessage.error(error);
  }
};

const dialogEditConfirm = async () => {
  try {
    dialogEdit.value = false
    const res = await updateScenario({
      projectName: form.value.projectName,
      data: editForm
    });
    if (res.success) {
      ElMessage.success("修改成功");
      getYaml();
    } else {
      ElMessage.error(res.msg);
    }
  } catch (error) {
    ElMessage.error(error);
  }
}

const handleEdit = async row => {
  editForm.scenario = row.scenario;
  editForm.targettime = row.targettime;
  editForm.concurrency = row.concurrency;
  editForm["ramp-up"] = row["ramp-up"];
  dialogEdit.value = true;
};

const dialogEdittimeConfirm = async () => {
  try {
    dialogEdittime.value = false
    const res = await updateTime({
      projectName: form.value.projectName,
      data: edittimeForm
    });
    if (res.success) {
      ElMessage.success("修改成功");
      getYaml();
    } else {
      ElMessage.error(res.msg);
    }
  } catch (error) {
    ElMessage.error(error);
  }
}

const handleEdittime = async row => {
  edittimeForm.Runtime = row;
  dialogEdittime.value = true;
};
const handleSizeChange = (val: number) => {
  pagination.value.pageSize = val
  getYaml()
}
const handleCurrentChange = (val: number) => {
  pagination.value.pageNum = val
  getYaml()
}

const handleTabChange = async (name) => {
  if (name === 'third') {
    if (!form.value.projectName) return;
    const res = await getJmeterLog({ projectName: form.value.projectName });
    if (res.success) {
      // ElMessage.success("查询成功");
      jmeterLogContent.value = res.data;
    } else {
      ElMessage.error(res.msg);
    }
  } else if (name === 'fourth') {
    if (!form.value.projectName) return;
    const res = await getTaurusLog({ projectName: form.value.projectName });
    if (res.success) {
      // ElMessage.success("查询成功");
      TaurusLogContent.value = res.data;
    } else {
      ElMessage.error(res.msg);
    }
  }
}
const handleClick = () => {

}
const handleDownloadJmeterlog = async () => {
  try {
    let filename = 'Jmeterlog.log'
    loading.value = true;
    const res = await downloadJmeterLog({
      projectName: form.value.projectName,
    });
    loading.value = false;
    downloadFileWithBuffer(res, filename, res.type);
  } catch (error) {
    loading.value = false;
    ElMessage.error(error);
  }
};
const handleDownloadTauruslog = async () => {
  try {
    let filename = 'Tauruslog.log'
    loading.value = true;
    const res = await downloadTaurusLog({
      projectName: form.value.projectName,
    });
    loading.value = false;
    downloadFileWithBuffer(res, filename, res.type);
  } catch (error) {
    loading.value = false;
    ElMessage.error(error);
  }
};



</script>

<template>
  <el-card class="box-card">
    <template #header>
      <div class="card-header">
        <span>执行测试</span>
      </div>
    </template>
    <div v-loading="loading" :element-loading-text="`${currentIp}正在执行...`">
      <el-form ref="ruleFormRef" :model="form" :rules="rules" inline>
        <el-form-item label="项目名" prop="projectName">
          <el-select filterable v-model="form.projectName" placeholder="请选择项目" @change="handleChange">
            <el-option v-for="item in projectList" :key="item" :label="item" :value="item" />
          </el-select>
        </el-form-item>
        <el-form-item label="选择测试机" prop="distributedValue" v-if="form.projectName">
          <el-input v-model="distributedString" placeholder="选择测试机" readonly @click="handleVisibleChange"
            style="width: 150px;" />
        </el-form-item>
        <el-form-item label="是否开启资源监控" v-if="form.projectName">
          <el-switch v-model="form.isMonitor" @change="handleIsMonitor" />
        </el-form-item>
        <el-form-item label="创建人"><el-input v-model="createrName" clearable disabled style="width: 150px;" />
        </el-form-item>

      </el-form>
      <el-collapse v-if="yamlConfig" v-loading="tableLoading" v-model="activeNames">
        <AddDialog v-model="dialogVisible" :projectName="form.projectName" @submit="handleAdd" />
        <el-collapse-item title="测试计划" name="1">
          <el-space style="margin-bottom: 10px;">
            <el-input v-model="searchScenario" clearable placeholder="请输入场景名" style="width: 200px;" />
            <el-button type="primary" @click="getYaml">搜索</el-button>
          </el-space>
          <YamlTable :projectName="form.projectName" :yamlConfig="yamlConfig" :pagination="pagination" @getYaml="getYaml"
            @handleSizeChange="handleSizeChange" @handleCurrentChange="handleCurrentChange"
            @handleSelectionChange="handleSelectionChange">
          </YamlTable>
        </el-collapse-item>
      </el-collapse>
    </div>
    <div class="form-footer">
      <el-button v-if="loading" type="danger" @click="stop">停止测试</el-button>
      <div>
        <el-button type="primary" @click="showTaskDialog" :loading="loading" :disabled="multipleSelection.length == 0">
          构建任务
        </el-button>
        <el-button type="primary" @click="run" :loading="loading" :disabled="multipleSelection.length == 0">
          执行测试
        </el-button>
      </div>
    </div>
    <el-tabs v-model="activeName" type="card" class="demo-tabs w-full h-full" @tab-change="handleTabChange"
      @tab-click="handleClick">
      <el-tab-pane label="执行日志" name="first">
        <div class="text" v-if="output.length != 0">
          <el-input v-model="output" readonly :rows="2" type="textarea" autosize />
        </div>
      </el-tab-pane>
      <el-tab-pane label="jmeter日志" name="third">
        <!-- <el-empty v-if="pageUrl.history.length === 0" description="暂无数据" /> -->
        <div style="display: flex; justify-content: flex-end;">
          <el-button circle size="small" :disabled="!form.projectName" @click="handleDownloadJmeterlog">
            <IconifyIconOffline :icon="Download" />
          </el-button>
        </div>

        <el-scrollbar :style="{ height: `${windowHeight - 380}px` }">
          <div class="text" v-if="jmeterLogContent.length != 0">
            <el-input v-model="jmeterLogContent" readonly :rows="2" type="textarea" autosize />
          </div>
        </el-scrollbar>

      </el-tab-pane>
      <el-tab-pane label="Taurus日志" name="fourth">
        <div style="display: flex; justify-content: flex-end;">
          <el-button circle size="small" :disabled="!form.projectName" @click="handleDownloadTauruslog">
            <IconifyIconOffline :icon="Download" />
          </el-button>
        </div>
        <el-scrollbar :style="{ height: `${windowHeight - 380}px` }">
          <!-- <el-empty v-if="pageUrl.history.length === 0" description="暂无数据" /> -->
          <div class="text" v-if="TaurusLogContent.length != 0">
            <el-input v-model="TaurusLogContent" readonly :rows="2" type="textarea" autosize />
          </div>
        </el-scrollbar>

      </el-tab-pane>
    </el-tabs>
    <el-dialog v-model="dialogFormVisible" title="选择测试机" width="500">
      <el-form :model="dialogForm">
        <el-form-item label="选择测试机">
          <el-select v-model="dialogForm.distributedValue" placeholder="请选择" multiple>
            <el-option v-for="  item   in   distributedOptions  " key="item" :label="item" :value="item" />
          </el-select>
        </el-form-item>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="dialogFormVisible = false" :loading="dialogLoading">取消</el-button>
          <el-button type="primary" :loading="dialogLoading" @click="handleUpdateDistributedValue">
            确定
          </el-button>
        </div>
      </template>
    </el-dialog>
    <el-dialog v-model="dialogEdit" title="编辑">
      <el-form :model="editForm" label-width="auto">
        <el-form-item :label="yamlLabel['scenario']">
          <el-input v-model="editForm.scenario" :value-on-clear="0" :min="0" :disabled="true" />
        </el-form-item>
        <el-form-item :label="yamlLabel['concurrency']">
          <el-input-number v-model="editForm.concurrency" :value-on-clear="0" :min="0" />
        </el-form-item>
        <el-form-item :label="yamlLabel['ramp-up']">
          <el-input-number v-model="editForm['ramp-up']" :value-on-clear="0" :min="0" />&nbsp s
        </el-form-item>
        <el-form-item :label="yamlLabel['targettime']">
          <el-input-number v-model="editForm.targettime" :value-on-clear="0" :min="0" />&nbsp ms
        </el-form-item>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="dialogEdit = false">取消</el-button>
          <el-button type="primary" @click="dialogEditConfirm">
            确定
          </el-button>
        </div>
      </template>
    </el-dialog>
    <el-dialog v-model="dialogEdittime" title="编辑">
      <el-form :model="edittimeForm" label-width="auto">
        <el-form-item :label="yamlLabel['Runtime']">
          <el-input-number v-model="edittimeForm.Runtime" :value-on-clear="0" :min="0" />
        </el-form-item>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="dialogEdittime = false">取消</el-button>
          <el-button type="primary" @click="dialogEdittimeConfirm">
            确定
          </el-button>
        </div>
      </template>
    </el-dialog>
    <!-- 构建任务选择时间 -->
    <el-dialog v-model="dialogTaskFormVisible" title="构建测试任务">
      <el-form :model="edittimeForm" label-width="auto">
        <el-form-item label="项目名">
          <el-input v-model="form.projectName" autocomplete="off" disabled />
        </el-form-item>
        <el-form-item label="压测机">
          <el-select v-model="dialogForm.distributedValue" placeholder="请选择" multiple disabled>
            <el-option v-for="  item   in   distributedOptions  " key="item" :label="item" :value="item" />
          </el-select>
        </el-form-item>
        <el-form-item label="已选场景">
          <el-input v-model="TaskForm.scenarioNames" autocomplete="off" />
        </el-form-item>
        <el-form-item label="选择测试时间">
          <div class="block" style="margin-right: 10px">
            <!-- <span class="demonstration">Default</span> -->
            <el-date-picker v-model="TaskForm.taskTime" type="datetime" placeholder="Select date and time" />
          </div>
          <el-checkbox v-model="checkAll" :indeterminate="isIndeterminate" @change="handleCheckAllChange">
            每周
          </el-checkbox>
        </el-form-item>
        <el-checkbox-group v-model="checkedWeek" @change="handleCheckedWeekChange">
          <el-checkbox v-for="week in weeks" :key="week" :label="week" :value="week">
            {{ week }}
          </el-checkbox>
        </el-checkbox-group>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="dialogTaskFormVisible = false">取消</el-button>
          <el-button type="primary" @click="submitTaskForm">
            确定
          </el-button>
        </div>
      </template>
    </el-dialog>
  </el-card>
</template>

<style lang="scss" scoped>
.card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-weight: 600;
}

.form-footer {
  margin-top: 20px;
  display: flex;
  justify-content: flex-end;
}

.text {
  margin-top: 20px;
}

.run-tips {
  font-size: 14px;
  color: red;
}


.demo-datetime-picker .block {
  padding: 30px 0;
  text-align: center;
  border-right: solid 1px var(--el-border-color);
  flex: 1;
}

.block:last-child {
  border-right: none;
}

.demonstration {
  display: block;
  color: var(--el-text-color-secondary);
  font-size: 14px;
  margin-bottom: 20px;
}
</style>
